package cn.com.bsfit.netty.config.conf;

import cn.com.bsfit.netty.config.base.BaseConfigurable;
import cn.com.bsfit.netty.config.base.OSInfo;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import cn.com.bsfit.netty.config.properties.BaseNettyServerProperties;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.Serializable;
import java.util.concurrent.*;

/**
 * 类名 NettyServerConfig
 * 描述 Netty服务端配置文件，只有当配置了netty.server.enable=true时，改配置文件才生效
 *
 * @author hedonglin
 * @version 1.0
 * @date 2019/9/29 10:08
 */
@Slf4j
@Configuration
@ConditionalOnProperty(prefix = "netty.server", name = "enable" ,havingValue = "true")
public class NettyServerConfig implements BaseConfigurable, Serializable {
    private static final long serialVersionUID = -5572317129641185304L;

    @Autowired(required = false)
    private BaseNettyServerProperties serverProperties;

    /**
     * 方法描述: 创建工作组线程池
     * @author hedonglin
     * @date 2019/9/29 10:13
     * @return {@link EventLoopGroup} EventLoopGroup
    */
    @Bean
    public EventLoopGroup workGroup() {
        int workers = serverProperties.getWorkers();
        // 如果使用多路复用
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("netty工作线程-%d").build();
        if (OSInfo.useNettyEpoll()) {
            EpollEventLoopGroup epollEventLoopGroup = new EpollEventLoopGroup(workers, threadFactory);
            epollEventLoopGroup.setIoRatio(100);
            return new EpollEventLoopGroup(serverProperties.getWorkers());
        }
        // 否则创建Nio线程池
        NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup(workers, threadFactory);
        nioEventLoopGroup.setIoRatio(100);
        return nioEventLoopGroup;
    }


    /**
     * 方法描述: Netty主线程池配置
     * @author hedonglin
     * @date 2019/9/29 10:21
     * @return {@link EventLoopGroup} EventLoopGroup
    */
    @Bean
    public EventLoopGroup bossGroup() {
        int bosses = serverProperties.getBosses();
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("netty主线程-%d").build();
        if (OSInfo.useNettyEpoll()) {
            log.info("当前运行操作系统为Linux，因此应用所采用的I/O多路复用机制为epoll");
            EpollEventLoopGroup epollEventLoopGroup=new EpollEventLoopGroup(bosses, threadFactory);
            epollEventLoopGroup.setIoRatio(100);
            return epollEventLoopGroup;
        }
        NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup(bosses, threadFactory);
        nioEventLoopGroup.setIoRatio(100);
        return nioEventLoopGroup;
    }

    /**
     * 启动Netty服务线程
     * @return ExecutorService
     */
    @Bean(destroyMethod = "shutdown",name="startNettyServerPool")
    public ScheduledExecutorService startNettyServerPool(){
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("启动Netty线程-%d").build();

        // 单线程启动
        return new ScheduledThreadPoolExecutor(
                1,
                namedThreadFactory,
                new ThreadPoolExecutor.AbortPolicy());
    }

    /**
     * 数据转换线程池配置
     * @return ExecutorService
     */
    @Bean(destroyMethod = "shutdown",name="dataTransactionPool")
    public ExecutorService dataTransactionPool(){
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("数据转换线程-%d").build();

        // 单线程启动
        return new ScheduledThreadPoolExecutor(
                serverProperties.getDataTransPollSize(),
                namedThreadFactory,
                new ThreadPoolExecutor.AbortPolicy());
    }
}
